﻿#include "MultipleLinearRegression.h"
#include <fstream>
#include <sstream>
#include <iostream>

#define _USE_MATH_DEFINES
#define WITHOUT_NUMPY
#include <matplotlibcpp.h>

bool MultipleLinearRegression::loadTrainDataFromCSV(std::string const &path)
{
	std::ifstream file(path);
	if (!file.is_open())
		return false;

	std::vector<std::pair<std::vector<double>, double>>().swap(trainData);
	std::string line, number;

	// 从第一行的标题获取属性个数，默认最后一个为标签
	std::getline(file, line);
	int d = std::count(line.begin(), line.end(), ',');
	_dim = d + 1;

	while (std::getline(file, line))
	{
		std::vector<double> _x(_dim);
		_x[0] = 1.0;
		double _label;

		std::stringstream ss(line);
		for (int i = 1; i < _dim; i++)
			std::getline(ss, number, ','), _x[i] = std::stod(number);
		ss >> _label;
		trainData.push_back(std::make_pair(_x, _label));
	}
	_size = trainData.size();
	std::cout << "Train Data imported: " << trainData.size() << '\n';
	return true;
}

bool MultipleLinearRegression::loadTestDataFromCSV(std::string const &path)
{
	std::ifstream file(path);
	if (!file.is_open())
		return false;

	std::vector<std::pair<std::vector<double>, double>>().swap(testData);
	std::string line, number;

	std::getline(file, line);

	while (std::getline(file, line))
	{
		std::vector<double> _x(_dim);
		_x[0] = 1.0;
		double _label;

		std::stringstream ss(line);
		for (int i = 1; i < _dim; i++)
			std::getline(ss, number, ','), _x[i] = std::stod(number);
		ss >> _label;
		testData.push_back(std::make_pair(_x, _label));
	}
	std::cout << "Test Data imported: " << testData.size() << '\n';

	return true;
}

void MultipleLinearRegression::setAlpha(double _alpha)
{
	alpha = _alpha;
}

void MultipleLinearRegression::calc(int iter)
{
	// 初始化权值
	w.reserve(_dim); w.resize(_dim);
	for (int i = 0; i < _dim; i ++)
		w[i] = 1.0;

	// 构建每个样本的权值记录，维护权值
	std::vector<std::vector<double>> _w;
	_w.reserve(_size); _w.resize(_size);
	for (int i = 0; i < _size; i ++)
	{
		_w[i].reserve(_dim); _w[i].resize(_dim);
		for (int j = 0; j < _dim; j ++)
			_w[i][j] = 1.0;
	}

	for (int i = 0, cnt = 0; i < iter; i ++, cnt ++)
	{
		double predictY = 0.0;
		for (int j = 0; j < _dim; j ++)
		{
			// 取第cnt个样本的特征进行计算
			predictY += w[j] * trainData[cnt % _size].first[j];
		}

		// 计算误差
		double error = predictY - trainData[cnt % _size].second;

		// 计算第cnt个样本的权值
		for (int j = 0; j < _dim; j ++)
		{
			w[j] -= alpha * error * trainData[cnt % _size].first[j] / _size;
		}
	}
}

void MultipleLinearRegression::test()
{
	double err = 0.0;
	int nums = testData.size();
	std::vector<int> realX, predictX;
	std::vector<double> realY, predictY;

	for (int i = 0; i < nums; i ++)
	{
		realX.push_back(i);
		predictX.push_back(i);
		realY.push_back(testData[i].second);
		double res = 0.0;
		for (int j = 0; j < _dim; j ++)
			res += w[j] * testData[i].first[j];
		err += fabs(res - testData[i].second);
		predictY.push_back(res);
	}
	err /= nums;
	std::cout << "平均误差为：" << err << '\n';

	matplotlibcpp::figure_size(800, 600);
	matplotlibcpp::title("Multiple Linear Regression");
	matplotlibcpp::named_plot("True value", realX, realY);
	matplotlibcpp::named_plot("Predicted value", predictX, predictY);
	matplotlibcpp::xlabel("Number of samples");
	matplotlibcpp::ylabel("Value");
	matplotlibcpp::legend();
	matplotlibcpp::show();
}